#ifndef __IENUM_IMPL_H__
#define __IENUM_IMPL_H__

#include "ibase_impl.h"

#include <vector>
#include <iterator>

namespace Boss
{

  class IEnumImpl
    : public CoClassBase
        <
          TL::TypeListAdapter
            <
              IEnum
            >
        >
  {
  public:
    BOSS_DECLARE_CLSID(6724ad4d-22eb-4d3d-bc0e-4283ef45373e)

      IEnumImpl()
      : IsModified(false)
    {
    }
    virtual ~IEnumImpl()
    {
    }

    // IEnum
    virtual TResult BOSS_CALL_TYPE First()
    {
      ISyncObject Lock(GetSynObj());
      IsModified = false;
      CurIter = Items.begin();
      return rcOk;
    }
    virtual TResult BOSS_CALL_TYPE Next(IBase **item)
    {
      ISyncObject Lock(GetSynObj());
      if (IsModified)
        return rcFail;
      if (CurIter == Items.end())
        return rcFalse;
      if ((*CurIter).QueryInterface(item) != rcOk)
        return rcFail;
      ++CurIter;
      return rcOk;
    }
    virtual TResult BOSS_CALL_TYPE Clone(IEnum **newEnum) const
    {
      ISyncObject Lock(GetSynObj());
      RefObjPtr<IEnumImpl> NewInst = IBaseImpl<IEnumImpl>::Create(GetSynObj());
      NewInst->Items = Items;
      if (!(NewInst->IsModified = IsModified))
      {
        NewInst->CurIter = NewInst->Items.begin() + std::distance(Items.begin(), CurIter);
      }
      return NewInst.QueryInterface(newEnum);
    }

    typedef RefObjPtr<IBase> IBasePtr;

    void AddItem(IBasePtr item)
    {
      ISyncObject Lock(GetSynObj());
      Items.push_back(item);
      IsModified = true;
    }
    void Clear()
    {
      ISyncObject Lock(GetSynObj());
      Items.clear();
      IsModified = true;
    }

  private:
    typedef std::vector<IBasePtr> IBasePtrPool;
    bool IsModified;
    mutable IBasePtrPool Items;
    typedef IBasePtrPool::iterator Iterator;
    Iterator CurIter;
  };

}

#endif  // !__IENUM_IMPL_H__
